💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    01 전반 구조, URL, 모델 | ✅저자: 이유정(박사)

    📅 Django + Tailwind Todo 프로젝트 (전반 구조, URL, 모델) 해석

    프로젝트 개요

    • 포탈을 조합한 Django 프로젝트로, 다양한 UI/가이드 파일과 TailwindCSS가 개입되어 있습니다.
    • Django 5.2, TailwindCSS 4.1, SQLite3(개발 DB)를 기본 환경으로 구성했습니다.

    GitHub - 소스 보기

    화면 구성

    1.메인화면

    메인화면

    2.회원가입

    회원가입

    3.로그인

    로그인

    4.Todo 목록

    Todo 목록

    5.Todo 등록

    Todo 등록

    6.Todo 수정

    Todo 수정

    📁 프로젝트 구조

    todoList_django2/
    │
    ├── accounts/            # 사용자 인증 및 관련 기능 앱
    ├── config/              # Django 설정 파일 (settings.py, urls.py 등)
    ├── node_modules/        # npm 패키지 저장소 (Tailwind 등 프론트엔드용)
    ├── static/              # 정적 파일(css, js 등)
    ├── templates/           # HTML 템플릿 폴더
    ├── todo/                # ToDo 기능 관련 앱
    │
    ├── .gitignore           # Git에서 제외할 파일 정의
    ├── db.sqlite3           # SQLite 데이터베이스 파일
    ├── manage.py            # Django 명령어 실행용 스크립트
    ├── package.json         # 프론트엔드 패키지 정의 (Tailwind 포함 예상)
    ├── pnpm-lock.yaml       # pnpm 패키지 잠금 파일
    ├── README.md            # 프로젝트 설명 문서
    ├── requirements.txt     # Python 패키지 목록
    ├── tailwind.config.js   # Tailwind CSS 설정 파일
    └── venv/                # 가상환경 폴더 (Python 패키지 독립 환경)
    
    
    📁 프로젝트 구조

    프로젝트 구조

    📁 todo 앱 디렉토리 구조

    todo/
    │
    ├── __pycache__/               # 파이썬 캐시 파일
    ├── migrations/                # 마이그레이션 파일 (DB 스키마 관리)
    │
    ├── templates/
    │   └── todo/
    │       ├── include/           # 공통 include 템플릿 폴더
    │       ├── base.html          # 기본 레이아웃 템플릿
    │       ├── head.html          # <head> 태그 관련 HTML 분리
    │       ├── header.html        # 일반 헤더
    │       ├── header-account.html # 로그인/계정 관련 헤더
    │       ├── footer.html        # 공통 푸터
    │       ├── todo_create.html   # 할 일 생성 페이지
    │       ├── todo_detail.html   # 할 일 상세 페이지
    │       ├── todo_list.html     # 할 일 목록 페이지
    │       └── todo_update.html   # 할 일 수정 페이지
    │
    ├── __init__.py                # 패키지 초기화
    ├── admin.py                   # Django 관리자 페이지 설정
    ├── apps.py                    # 앱 구성 정보
    ├── form.py                    # 폼 클래스 정의 (Form, ModelForm 등)
    ├── models.py                  # DB 모델 정의 (ToDo 모델 등)
    ├── tests.py                   # 테스트 코드
    ├── urls.py                    # URL 라우팅 정의
    └── views.py                   # 뷰 함수/클래스 정의
    
    📁 todo 앱 디렉토리 구조

    todo 앱 디렉토리 구조

    ⚙️ 개발 환경

    • Python 3.12.3
    • Django 5.2.1
    • 가상환경: venv 사용
    • tailwindcss v4.1 사용

    ✅ Django settings.py 주의할 설정 항목 정리


    🔒 1. 보안 관련 설정

    ✅ SECRET_KEY

    SECRET_KEY = 'django-insecure-...'
    
    • Django 프로젝트의 핵심 보안 키로, 절대 외부에 노출되면 안 됨
    • 실제 서비스에서는 .env 파일로 분리하거나 환경변수로 관리 필요

    ✅ DEBUG

    DEBUG = True
    
    • 개발 환경에서는 True로 설정 가능
    • 배포 시에는 반드시 False로 설정해야 함
    • False일 때만 Django가 보안 기능(에러 페이지 숨김 등)을 제대로 작동함

    ✅ ALLOWED_HOSTS

    ALLOWED_HOSTS = []
    
    • 비워두면 외부 요청 거부됨

    • 배포 시에는 반드시 도메인이나 IP를 지정해야 함

      ALLOWED_HOSTS = ['yourdomain.com', '127.0.0.1']
      

    📁 2. 정적 파일 설정

    ✅ STATICFILES_DIRS

    STATICFILES_DIRS = [ BASE_DIR / "static" ]
    
    • 개발 환경에서 정적 파일을 불러오기 위해 사용
    • 운영 환경에서는 STATIC_ROOT도 설정 후 collectstatic 명령 필요

    🔧 추가 필요 (운영 환경)

    STATIC_ROOT = BASE_DIR / "staticfiles"
    
    • python manage.py collectstatic 실행 시 이 경로로 파일이 복사됨

    🧩 3. 템플릿 설정

    ✅ TEMPLATES["DIRS"]

    "DIRS": [BASE_DIR / "templates"]
    
    • 전역 템플릿 폴더 경로
    • 각 앱의 templates/ 폴더와 충돌하지 않도록 주의

    🔐 4. 로그인/로그아웃 관련

    ✅ 로그인/로그아웃 후 리디렉션 경로

    LOGIN_REDIRECT_URL = "/todo/"
    LOGOUT_REDIRECT_URL = "/accounts/login/"
    
    • 실제 해당 경로가 존재해야 하며, 설정이 잘못되면 로그인 후 오류 발생 가능

    🌍 5. 시간대 및 지역 설정

    ✅ TIME_ZONE, USE_TZ

    TIME_ZONE = 'Asia/Seoul'
    USE_TZ = True
    
    • USE_TZ=True이면 DB에는 UTC로 저장되고, 템플릿에서는 TIME_ZONE 기준으로 변환됨
    • 시간대 오차 발생 여부 주의

    🗃 6. 데이터베이스 설정

    ✅ SQLite 사용 (기본값)

    DATABASES = {
      'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
      }
    }
    
    • 가볍고 편리하지만, 운영 환경에서는 PostgreSQL/MySQL로 변경 권장

    ✅ 추가로 고려할 사항

    • .env 환경 파일 분리
    • 이메일 설정 (에러 알림용)
    • CORS 설정 (API 연동 시 필요)
    • 보안 관련 미들웨어 강화 (예: XSS, CSRF 정책 추가)

    가상 URL Routing 해석

    ▶ config/urls.py

    urlpatterns = [
        path('admin/', admin.site.urls),    
        path("todo/", include("todo.urls")),
        path("", root_index_view),  # 루트 / 메인 index.html 보이게
    
        path("accounts/", include("accounts.urls")),
        path("accounts/", include("django.contrib.auth.urls")),
    
        path('signup/', signup_redirect_view),
        path('login/', login_redirect_view),
    ]
    
    • / : 우선 index.html 개입
    • /todo/ : ToDo 앱과 관련된 건 모두 바이네이션
    • /accounts/ : 로그인, 회원가입, 비밀번호 교체 등 계정 관리

    ▶ todo/urls.py

    urlpatterns = [
        path("", TodoListView.as_view(), name="todo_list"),
        path("create/", TodoCreateView.as_view(), name="todo_create"),
        path("<int:pk>/", TodoDetailView.as_view(), name="todo_detail"),
        path("<int:pk>/update/", TodoUpdateView.as_view(), name="todo_update"),
        path("<int:pk>/delete/", TodoDeleteView.as_view(), name="todo_delete"),
    ]
    
    • /todo/ : 목록 페이지
    • /todo/create/ : 새 할일 등록
    • /todo/3/ : ID=3 할일 상세 보기
    • /todo/3/update/ : 할일 수정
    • /todo/3/delete/ : 할일 삭제

    ▶ Todo 목록 모델 (models.py)

    class Todo(models.Model):
        author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="작성자")
        name = models.CharField("이름", max_length=100)
        description = models.TextField("설명", blank=True)
        complete = models.BooleanField("완료 유무", default=False)
        exp = models.PositiveIntegerField("경험치", default=0)
        completed_at = models.DateTimeField("완료 시간", null=True, blank=True)
        created_at = models.DateTimeField("생성 시간", auto_now_add=True)
        updated_at = models.DateTimeField("수정 시간", auto_now=True)
    
        def clean(self):
            if self.complete and self.completed_at is None:
                raise ValidationError("\uc644\ub8cc\ub41c \ud56d\ubaa9\uc740 completed_at \ub0a0\uc9dc\uac00 \ud544\uc694\ud569\ub2c8\ub2e4.")
    
        def save(self, *args, **kwargs):
            if self.complete and self.completed_at is None:
                self.completed_at = timezone.now()
            elif not self.complete:
                self.completed_at = None
            super().save(*args, **kwargs)
    
        class Meta:
            verbose_name = "\ud560 \uc77c"
            verbose_name_plural = "\ud560 \uc77c \ubaa9\ub85d"
    

    🔍 이 로직의 장점

    • clean()에서 완료 상태에 맞는 유효성 검사를 선행 → 데이터 일관성 유지

    • save()에서 completed_at 자동 세팅 → 개발자 편의성과 실수 방지

    • admin, form, API 등 여러 입력 경로에서도 일관된 처리 가능

    단점 설명

    • 그룹 목록에 충분한 정보 (작성자, 이름, 설명, 경험치, 완료 유무)가 포함됨
    • clean() 를 통해 목록 유효성 검사 수행
    • save() 메소드를 통해 자동으로 completed_at 처리

    ✅ Todo 모델 상세 설명

    from django.db import models
    from django.utils import timezone
    from django.core.exceptions import ValidationError
    from django.contrib.auth import get_user_model
    
    • get_user_model()은 현재 프로젝트에서 사용하는 사용자 모델을 반환합니다. 기본적으로는 auth.User지만, 커스텀 유저 모델을 사용하는 경우에도 자동으로 연결됩니다.

    📦 모델 정의: Todo

    class Todo(models.Model):
        author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="작성자")
        name = models.CharField("이름", max_length=100)
        description = models.TextField("설명", blank=True)
        complete = models.BooleanField("완료 여부", default=False)
        exp = models.PositiveIntegerField("경험치", default=0)
        completed_at = models.DateTimeField("완료 시각", null=True, blank=True)
        created_at = models.DateTimeField("생성 시각", auto_now_add=True)
        updated_at = models.DateTimeField("수정 시각", auto_now=True)
    

    🔸 필드 설명

    필드명 타입 설명
    author ForeignKey(User) 작성자 (로그인한 사용자와 연결됨)
    name CharField 할 일 제목, 최대 100자 제한
    description TextField 상세 설명, 비워둘 수 있음
    complete BooleanField 완료 여부 (True/False)
    exp PositiveIntegerField 이 할 일의 경험치 (0 이상 정수)
    completed_at DateTimeField 완료된 시점, 완료 안 했으면 빈 값 가능
    created_at DateTimeField 처음 생성된 시각 (자동 저장)
    updated_at DateTimeField 마지막으로 수정된 시각 (자동 저장)

    🧪 clean() 메서드

    def clean(self):
        if self.complete and self.completed_at is None:
            raise ValidationError("완료된 항목은 completed_at 날짜가 필요합니다.")
    
    • 모델 유효성 검사 로직을 정의

    • 완료된 항목(complete=True)인데 완료시각(completed_at)이 없다면 예외 발생

    • 주석 처리된 반대 조건도 활용 가능:

      if not self.complete and self.completed_at is not None:
          raise ValidationError("완료되지 않은 항목은 completed_at 날짜를 가질 수 없습니다.")
      

    💾 save() 메서드 오버라이드

    def save(self, *args, **kwargs):
        if self.complete and self.completed_at is None:
            self.completed_at = timezone.now()
        elif not self.complete:
            self.completed_at = None
        super().save(*args, **kwargs)
    
    • 저장 직전에 완료 상태에 따라 completed_at 필드 자동 설정
    • complete = True인데 completed_at이 없다면 현재 시각으로 자동 설정
    • complete = False라면 completed_at은 무조건 None 처리 (초기화)

    🔧 Meta 클래스 및 문자열 표현

    class Meta:
        verbose_name = "할 일"
        verbose_name_plural = "할 일 목록"
    
    def __str__(self):
        return f"이름: {self.name}, 설명: {self.description}, 완료: {self.complete}, 경험치: {self.exp}, 완료시각: {self.completed_at}"
    
    • Meta 클래스는 관리자 페이지 등에서의 모델 명칭 지정
    • __str__()은 객체를 문자열로 표현할 때 출력되는 포맷 지정

    ✅ 핵심 요약

    기능 역할
    작성자 연결 로그인 사용자와 각 할 일을 연결함
    유효성 검사 완료된 항목에는 완료시각이 있어야 함
    자동 처리 완료 시점 자동 저장 (save() 활용)
    경험치 시스템 할 일 완료 시 보상처럼 사용할 수 있음

    🔗 관련 기능 흐름도 예시

    1. 사용자 할 일 작성 → TodoCreateView에서 save() 호출
    2. 체크박스로 완료 여부 선택 시, completed_at 자동 기록
    3. 수정 시 완료 여부 변경하면 save()가 적절히 동작
    4. 관리자 페이지에서도 __str__() 덕분에 요약 정보 확인 가능
    TOP
    preload preload